/*
 * Copyright (c) United Binary LLC.  All rights reserved.
 * 
 * This code is licensed under the MIT License
 * 
 * SEE: http://harnessit.codeplex.com/license
 * 
 */
using System;
using System.ComponentModel;
using System.Runtime.Serialization;

namespace UnitedBinary.UnitTests.Framework.TestItems
{
	/// <include file='comments.xml' path='Docs/TestException/Class/*'/>
	[Serializable]
	[EditorBrowsable(EditorBrowsableState.Never)]
	public sealed class TestException
	{
		private string message = "";
		private string source = "";
		private TestExceptionType myType = new TestExceptionType(typeof(System.Exception));
		private string toString = "";
		private string stackTrace = "";
		private int threadID = 0;
		private string threadName = "";

		private TestException innerException = null;

		/// <include file='comments.xml' path='Docs/TestException/ctor/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public TestException()
		{
		}

		/// <include file='comments.xml' path='Docs/TestException/ctor_Exception/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public TestException(System.Exception e)
		{
			LoadFromException(e);
		}

		/// <include file='comments.xml' path='Docs/TestException/LoadFromException/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public void LoadFromException(System.Exception e)
		{
			if (e == null)
			{
				throw new ArgumentNullException("e", "The exception cannot be null for LoadFromException in TestException.");
			}

			//
			// What follows is some bizarre error handling. Here's the logic behind it.
			// if e.Source is null (for example), it seems that even this line:
			// 
			//        if (e.Source != null)
			// 
			// throws a NullArgumentException! Is this by design or a bug? Don't know but
			// the wrapping try/catches solve the problem here as far as we are concerned.
			//

			//
			// Process the Message value.
			//
			try
			{
				if (e.Message != null)
				{
					this.Message = e.Message;
				}
				else 
				{
					this.Message = "null";
				}
			}
			catch { this.Message = "null"; }

			//
			// Process the Source value.
			//
			try
			{
				if (e.Source != null)
				{
					this.Source = e.Source;
				}
				else
				{
					this.Source = "null";
				}
			}
			catch { this.Source = "null"; }

			//
			// Process the ToString() value.
			//
			try
			{
				string toString = e.ToString();
				if (toString != null)
				{
					this.ToStringText = e.ToString();
				}
				else
				{
					this.ToStringText = "null";
				}
			}
			catch (Exception ex)
			{
				this.ToStringText = "Unavailable.\n\nDetails: " + ex.ToString();
			}

			//
			// Process the StackTrace value.
			//
			try
			{
				if (e.StackTrace != null)
				{
					this.StackTrace = e.StackTrace;
				}
				else
				{
					this.StackTrace = "null";
				}
			}
			catch (Exception ex2)
			{
				this.StackTrace = "Unavailable.\n\nDetails: " + ex2.ToString();
			}

			//
			// Process the Type value.
			//
			this.Type = new TestExceptionType(e.GetType());
			
			//
			// Process the InnerException value.
			//
			try
			{
				if (e.InnerException != null)
				{
					this.InnerException = new TestException(e.InnerException);
				}
			}
			catch { }
		}

		/// <include file='comments.xml' path='Docs/TestException/Message/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public string Message
		{
			get
			{
				return message;
			}
			set
			{
				message = value;

				if (message == null)
				{
					message = "";
				}
			}
		}

		/// <include file='comments.xml' path='Docs/TestException/Source/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public string Source
		{
			get
			{
				return source;
			}
			set
			{
				source = value;

				if (source == null)
				{
					source = "";
				}
			}
		}

		/// <include file='comments.xml' path='Docs/TestException/Type/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public TestExceptionType Type
		{
			get
			{
				return myType;
			}
			set
			{
				myType = value;

				if (myType == null)
				{
					myType = new TestExceptionType(typeof(System.Exception));
				}
			}
		}


		/// <include file='comments.xml' path='Docs/TestException/ToStringText/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public string ToStringText
		{
			get
			{
				return toString;
			}
			set
			{
				toString = value;

				if (toString == null)
				{
					toString = "";
				}
			}
		}

		/// <include file='comments.xml' path='Docs/TestException/StackTrace/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public string StackTrace
		{
			get
			{
				return stackTrace;
			}
			set
			{
				stackTrace = value;

				if (stackTrace == null)
				{
					stackTrace = "";
				}
			}
		}

		/// <include file='comments.xml' path='Docs/TestException/InnerException/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public TestException InnerException
		{
			get
			{
				return innerException;
			}
			set
			{
				innerException = value;
			}
		}

		/// <include file='comments.xml' path='Docs/TestException/ThreadName/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public string ThreadName
		{
			get
			{
				return threadName;
			}
			set
			{
				threadName = value;
				if (threadName == null)
				{
					threadName = "";
				}
				threadName = threadName.Trim();

				//
				// Use recursion to set name for the inner exception(s).
				//
				if (this.InnerException != null)
				{
					this.InnerException.ThreadName = threadName;
				}
			}
		}

		/// <include file='comments.xml' path='Docs/TestException/ThreadID/*'/>
		[EditorBrowsable(EditorBrowsableState.Never)]
		public int ThreadID
		{
			get
			{
				return threadID;
			}
			set
			{
				threadID = value;

				//
				// Use recursion to set ID for the inner exception(s).
				//
				if (this.InnerException != null)
				{
					this.InnerException.ThreadID = threadID;
				}
			}
		}
	}
}
